﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Linq.Expressions;
using System.Windows.Forms;

namespace AMM.CustomWinControls {

    #region Sequence column

    [ToolboxBitmap(typeof(DataGridViewTextBoxColumn))]
    public class DataGridViewSequenceColumnEx : DataGridViewColumn {
        public DataGridViewSequenceColumnEx() {
            this.CellTemplate = new DataGridViewSequenceCellEx();
            this.ReadOnly = true;
        }
    }

    public class DataGridViewSequenceCellEx : DataGridViewCell {
        protected override void Paint(
            Graphics graphics,
            Rectangle clipBounds,
            Rectangle cellBounds,
            int rowIndex,
            DataGridViewElementStates cellState,
            object value,
            object formattedValue,
            string errorText,
            DataGridViewCellStyle cellStyle,
            DataGridViewAdvancedBorderStyle advancedBorderStyle,
            DataGridViewPaintParts paintParts) {
            // Draw the cell background, if specified. 
            if ((paintParts & DataGridViewPaintParts.Background) ==
                DataGridViewPaintParts.Background) {
                SolidBrush cellBackground = new SolidBrush(cellStyle.BackColor);
                graphics.FillRectangle(cellBackground, cellBounds);
                cellBackground.Dispose();
            }

            // Draw the cell borders, if specified. 
            if ((paintParts & DataGridViewPaintParts.Border) ==
                DataGridViewPaintParts.Border) {
                PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
            }

            using (SolidBrush text = new SolidBrush(cellStyle.ForeColor)) {
                using (StringFormat textFormat = new StringFormat()) {
                    textFormat.Alignment = StringAlignment.Center;
                    textFormat.LineAlignment = StringAlignment.Center;
                    graphics.DrawString((rowIndex + 1).ToString(), cellStyle.Font, text, cellBounds, textFormat);
                }
            }
        }
    }

    #endregion

    #region Datetime picker column

    [ToolboxBitmap(typeof(DataGridViewTextBoxColumn))]
    public class DataGridViewDateTimePickerColumnEx : DataGridViewColumn {
        public DataGridViewDateTimePickerColumnEx() {
            this.CellTemplate = new DataGridViewDateTimePickerCellEx();
        }
    }

    public class DataGridViewDateTimePickerCellEx : DataGridViewTextBoxCell {

        public DataGridViewDateTimePickerCellEx()
            : base() {
            this.Style.Format = "d";
        }

        public override void InitializeEditingControl(int rowIndex, object
            initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) {
            // Set the value of the editing control to the current cell value. 
            base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
            CalendarEditingControl ctl = DataGridView.EditingControl as CalendarEditingControl;
            // Use the default row value when Value property is null. 
            if (this.Value == null) {
                ctl.Value = (DateTime)this.DefaultNewRowValue;
            }
            else {
                try {
                    ctl.Value = (DateTime)this.Value;
                }
                catch {
                    ctl.Value = (DateTime)this.DefaultNewRowValue;
                }
            }
        }

        public override Type EditType {
            get {
                return typeof(CalendarEditingControl);
            }
        }

        public override Type ValueType {
            get {
                return typeof(DateTime);
            }
        }

        public override object DefaultNewRowValue {
            get {
                return DateTime.Now;
            }
        }
    }

    internal sealed class CalendarEditingControl : DateTimePicker, IDataGridViewEditingControl {
        DataGridView dataGridView;
        private bool valueChanged = false;
        int rowIndex;

        public CalendarEditingControl() {
            this.Format = DateTimePickerFormat.Short;
        }

        public object EditingControlFormattedValue {
            get {
                return this.Value.ToShortDateString();
            }
            set {
                if (value is String) {
                    try {
                        this.Value = DateTime.Parse((String)value);
                    }
                    catch {
                        this.Value = DateTime.Now;
                    }
                }
            }
        }

        public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) {
            return EditingControlFormattedValue;
        }

        public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) {
            this.Font = dataGridViewCellStyle.Font;
            this.CalendarForeColor = dataGridViewCellStyle.ForeColor;
            this.CalendarMonthBackground = dataGridViewCellStyle.BackColor;
        }

        public int EditingControlRowIndex {
            get {
                return rowIndex;
            }
            set {
                rowIndex = value;
            }
        }

        public bool EditingControlWantsInputKey(Keys key, bool dataGridViewWantsInputKey) {
            // Let the DateTimePicker handle the keys listed. 
            switch (key & Keys.KeyCode) {
                case Keys.Left:
                case Keys.Up:
                case Keys.Down:
                case Keys.Right:
                case Keys.Home:
                case Keys.End:
                case Keys.PageDown:
                case Keys.PageUp:
                    return true;
                default:
                    return !dataGridViewWantsInputKey;
            }
        }

        public void PrepareEditingControlForEdit(bool selectAll) {
            // No preparation needs to be done.
        }

        public bool RepositionEditingControlOnValueChange {
            get {
                return false;
            }
        }

        public DataGridView EditingControlDataGridView {
            get {
                return dataGridView;
            }
            set {
                dataGridView = value;
            }
        }

        public bool EditingControlValueChanged {
            get {
                return valueChanged;
            }
            set {
                valueChanged = value;
            }
        }

        public Cursor EditingPanelCursor {
            get {
                return base.Cursor;
            }
        }

        protected override void OnValueChanged(EventArgs eventargs) {
            // Notify the DataGridView that the contents of the cell have changed.
            valueChanged = true;
            this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
            base.OnValueChanged(eventargs);
        }
    }

    #endregion

    #region Listbox column

    [ToolboxBitmap(typeof(DataGridViewCheckBoxColumn))]
    public class DataGridViewCheckedListBoxColumnEx : DataGridViewColumn {
        public DataGridViewCheckedListBoxColumnEx() {
            this.CellTemplate = new DataGridViewCheckedListBoxCellEx();
        }
        public List<string> Items { get; set; }
    }

    public class DataGridViewCheckedListBoxCellEx : DataGridViewTextBoxCell {

        public DataGridViewCheckedListBoxCellEx()
            : base() {
        }

        public override void InitializeEditingControl(int rowIndex,
            object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) {
            // Set the value of the editing control to the current cell value. 
            base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);

            DataGridViewCheckedListBoxColumnEx originColumn = (DataGridViewCheckedListBoxColumnEx)this.OwningColumn;
            CheckedListBoxEditingControl ctl = this.DataGridView.EditingControl as CheckedListBoxEditingControl;
            ctl.ValueEx = initialFormattedValue;
            ctl.ItemsEx = originColumn.Items;
            if (initialFormattedValue != null) {
                ctl.SelectedItemsEx = initialFormattedValue.ToString().Split(';').ToList();
            }
        }

        public override Type EditType {
            get { return typeof(CheckedListBoxEditingControl); }
        }

        public override Type ValueType {
            get { return typeof(string); }
        }

        public override object DefaultNewRowValue {
            get { return string.Empty; }
        }
    }

    internal sealed class CheckedListBoxEditingControl : CheckedListBoxDropDownEx, IDataGridViewEditingControl {

        public CheckedListBoxEditingControl() {
            this.ValueChanged += new EventHandler(CheckedListBoxEditingControl_ValueChanged);
        }

        void CheckedListBoxEditingControl_ValueChanged(object sender, EventArgs e) {
            this._valueChanged = true;
            this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
        }

        #region Implemented IDataGridViewEditingControl interface

        private bool _valueChanged = false;
        int _rowIndex;
        DataGridView _dataGridView;

        public object EditingControlFormattedValue {
            get { return this.ValueEx; }
            set {
                if (value is String) { this.ValueEx = value; }
            }
        }

        public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) {
            return EditingControlFormattedValue;
        }

        public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) {
            this.Font = dataGridViewCellStyle.Font;
            this.ForeColor = dataGridViewCellStyle.ForeColor;
            this.BackColor = dataGridViewCellStyle.BackColor;
        }

        public int EditingControlRowIndex {
            get { return _rowIndex; }
            set { _rowIndex = value; }
        }

        public bool EditingControlWantsInputKey(Keys key, bool dataGridViewWantsInputKey) {
            // Let the DateTimePicker handle the keys listed. 
            switch (key & Keys.KeyCode) {
                case Keys.Left:
                case Keys.Up:
                case Keys.Down:
                case Keys.Right:
                case Keys.Home:
                case Keys.End:
                case Keys.PageDown:
                case Keys.PageUp:
                    return true;
                default:
                    return !dataGridViewWantsInputKey;
            }
        }

        public void PrepareEditingControlForEdit(bool selectAll) {
            // No preparation needs to be done.
        }

        public bool RepositionEditingControlOnValueChange {
            get { return false; }
        }

        public DataGridView EditingControlDataGridView {
            get { return _dataGridView; }
            set { _dataGridView = value; }
        }

        public bool EditingControlValueChanged {
            get { return _valueChanged; }
            set { _valueChanged = value; }
        }

        public Cursor EditingPanelCursor {
            get { return base.Cursor; }
        }

        #endregion
    }

    #endregion

    #region DataGridView column

    [ToolboxBitmap(typeof(DataGridViewComboBoxColumn))]
    public class DataGridViewSelfColumnEx : DataGridViewColumn {
        public DataGridViewSelfColumnEx() {
            this.CellTemplate = new DataGridViewSelfCellEx();
        }
        public int WidthEx { get; set; }
        public int HeightEx { get; set; }
        public int PageSizeEx { get; set; }
        public string DisplayMemberEx { get; set; }
        public string ValueMemberEx { get; set; }
        public object SelectedValueEx { get; set; }
        public object SelectedItemEx { get; set; }
        public List<object> DataGridViewSourceEx { get; private set; }

        public Type DataGridViewModelType { get; private set; }
        public List<string> ShowColumnNames { get; private set; }

        public void DataBind<TViewModel, TViewModelProperties>(TViewModel viewModel,
            Expression<Func<TViewModel, TViewModelProperties>> viewModelAccessor, List<TViewModel> datasoruce) {
            if (viewModelAccessor.NodeType != ExpressionType.Lambda) {
                throw new ArgumentNullException("The viewModelAccessor is not a valid lambda expression.");
            }
            this.ShowColumnNames = new List<string>();
            this.DataGridViewModelType = typeof(TViewModel);
            this.DataGridViewSourceEx = datasoruce.Cast<object>().ToList();

            LambdaExpression lambdaExpression = ((LambdaExpression)viewModelAccessor);
            if (lambdaExpression.Body.NodeType == ExpressionType.MemberAccess) {
                MemberExpression memberExpression = (MemberExpression)lambdaExpression.Body;
                this.ShowColumnNames.Add(memberExpression.Member.Name);
            }
            if (lambdaExpression.Body.NodeType == ExpressionType.New) {
                NewExpression newExpression = (NewExpression)lambdaExpression.Body;
                newExpression.Members.ToList().ForEach(x => { this.ShowColumnNames.Add(x.Name); });
            }
        }
    }

    public class DataGridViewSelfCellEx : DataGridViewTextBoxCell {

        private object GetCurrentValue(object originalValue) {
            object val = null;
            DataGridViewSelfColumnEx originColumn = (DataGridViewSelfColumnEx)this.OwningColumn;
            object item = originColumn.DataGridViewSourceEx.FirstOrDefault(x => x.GetType().GetProperty(originColumn.ValueMemberEx).GetValue(x, null).Equals(originalValue));
            if (item != null) { val = item.GetType().GetProperty(originColumn.DisplayMemberEx).GetValue(item, null); }

            return val;
        }

        public DataGridViewSelfCellEx()
            : base() { }

        public override void InitializeEditingControl(int rowIndex,
            object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) {
            // Set the value of the editing control to the current cell value. 
            base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);

            DataGridViewSelfColumnEx originColumn = (DataGridViewSelfColumnEx)this.OwningColumn;
            SelfEditingControl ctl = this.DataGridView.EditingControl as SelfEditingControl;
            object itemContainter = this.DataGridView.Rows[rowIndex].DataBoundItem;
            object selectedValueEx = null, valueEx = null;
            if (itemContainter != null) { selectedValueEx = itemContainter.GetType().GetProperty(originColumn.DataPropertyName).GetValue(itemContainter, null); }
            object item = originColumn.DataGridViewSourceEx.FirstOrDefault(x => x.GetType().GetProperty(originColumn.ValueMemberEx).GetValue(x, null).Equals(selectedValueEx));
            if (item != null) { valueEx = item.GetType().GetProperty(originColumn.DisplayMemberEx).GetValue(item, null); }

            ctl.WidthEx = originColumn.WidthEx;
            ctl.HeightEx = originColumn.HeightEx;
            ctl.PageSizeEx = originColumn.PageSizeEx;
            ctl.DisplayMemberEx = originColumn.DisplayMemberEx;
            ctl.ValueMemberEx = originColumn.ValueMemberEx;
            ctl.DataBind(originColumn.DataGridViewModelType, originColumn.ShowColumnNames, originColumn.DataGridViewSourceEx);
            ctl.SelectedValueEx = selectedValueEx;
            ctl.ValueEx = valueEx;
            ctl.SelectedItemEx = item;
        }

        protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex,
            DataGridViewElementStates cellState, object value, object formattedValue, string errorText,
            DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) {
            if (this.DataGridView != null) {
                object val = this.GetCurrentValue(value);
                base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, val, errorText, cellStyle, advancedBorderStyle, paintParts);
            }
            else {
                base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
            }
        }

        protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle,
            TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context) {
            object val = this.GetCurrentValue(value);
            return base.GetFormattedValue(val, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context);
        }

        /*
        protected override object GetValue(int rowIndex) {
            if (this.DataGridView != null &&
                this.DataGridView.EditingControl != null &&
                this.DataGridView.EditingControl is SelfEditingControl) {
                return ((SelfEditingControl)DataGridView.EditingControl).SelectedValueEx;
            }
            else {
                return base.GetValue(rowIndex);
            }
        }

        protected override bool SetValue(int rowIndex, object value) {
            if (this.DataGridView != null &&
                this.DataGridView.EditingControl != null &&
                this.DataGridView.EditingControl is SelfEditingControl) {
                return base.SetValue(rowIndex, ((SelfEditingControl)DataGridView.EditingControl).SelectedValueEx);
            }
            else {
                return base.SetValue(rowIndex, value);
            }
        }
        */

        public override Type EditType {
            get { return typeof(SelfEditingControl); }
        }

        public override Type ValueType {
            get { return typeof(object); }
        }

        public override object DefaultNewRowValue {
            get { return null; }
        }
    }

    internal sealed class SelfEditingControl : DataGridViewDropDownEx, IDataGridViewEditingControl {

        public SelfEditingControl() {
            this.ValueChanged += (s, e) => {
                this._valueChanged = true;
                this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
            };
        }

        public new void DataBind(Type viewModelType, List<string> showColumnNames, List<object> datasource) {
            base.DataBind(viewModelType, showColumnNames, datasource);
            this.DropDownShowed += (s, e) => {
                base.DataBind(viewModelType, showColumnNames, datasource);
            };
        }

        #region Implemented IDataGridViewEditingControl interface

        private bool _valueChanged = false;
        int _rowIndex;
        DataGridView _dataGridView;

        public object EditingControlFormattedValue {
            get { return this.SelectedValueEx; }
            set { this.SelectedValueEx = value; }
        }

        public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) {
            if (this.ValueEx != null && !string.IsNullOrEmpty(this.ValueEx.ToString())) {
                return this.EditingControlFormattedValue;
            }
            return this.ValueEx;
        }

        public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) {
            this.Font = dataGridViewCellStyle.Font;
            this.ForeColor = dataGridViewCellStyle.ForeColor;
            this.BackColor = dataGridViewCellStyle.BackColor;
        }

        public int EditingControlRowIndex {
            get { return _rowIndex; }
            set { _rowIndex = value; }
        }

        public bool EditingControlWantsInputKey(Keys key, bool dataGridViewWantsInputKey) {
            // Let the DateTimePicker handle the keys listed. 
            switch (key & Keys.KeyCode) {
                case Keys.Left:
                case Keys.Up:
                case Keys.Down:
                case Keys.Right:
                case Keys.Home:
                case Keys.End:
                case Keys.PageDown:
                case Keys.PageUp:
                    return true;
                default:
                    return !dataGridViewWantsInputKey;
            }
        }

        public void PrepareEditingControlForEdit(bool selectAll) {
            // No preparation needs to be done.
        }

        public bool RepositionEditingControlOnValueChange {
            get { return false; }
        }

        public DataGridView EditingControlDataGridView {
            get { return _dataGridView; }
            set { _dataGridView = value; }
        }

        public bool EditingControlValueChanged {
            get { return _valueChanged; }
            set { _valueChanged = value; }
        }

        public Cursor EditingPanelCursor {
            get { return base.Cursor; }
        }

        #endregion
    }

    #endregion

    #region Checkbox column can select all

    #region GridViewCheckBoxColumn

    [System.Drawing.ToolboxBitmap(typeof(DataGridViewCheckBoxColumn))]
    public class DataGridViewCheckBoxColumnCanSelectAllEx : DataGridViewCheckBoxColumn {
        #region Constructor

        public DataGridViewCheckBoxColumnCanSelectAllEx() {
            DatagridViewCheckBoxHeaderCell datagridViewCheckBoxHeaderCell = new DatagridViewCheckBoxHeaderCell();

            this.HeaderCell = datagridViewCheckBoxHeaderCell;
            this.Width = 50;

            datagridViewCheckBoxHeaderCell.OnCheckBoxClicked += new CheckBoxClickedHandler(datagridViewCheckBoxHeaderCell_OnCheckBoxClicked);

        }

        #endregion

        #region Methods

        void datagridViewCheckBoxHeaderCell_OnCheckBoxClicked(int columnIndex, bool state) {
            DataGridView.RefreshEdit();

            foreach (DataGridViewRow row in this.DataGridView.Rows) {
                if (!row.Cells[columnIndex].ReadOnly) {
                    row.Cells[columnIndex].Value = state;
                }
            }
            DataGridView.RefreshEdit();
        }



        #endregion
    }

    #endregion

    #region DatagridViewCheckBoxHeaderCell

    public delegate void CheckBoxClickedHandler(int columnIndex, bool state);
    public class DataGridViewCheckBoxHeaderCellEventArgs : EventArgs {
        bool _bChecked;
        public DataGridViewCheckBoxHeaderCellEventArgs(int columnIndex, bool bChecked) {
            _bChecked = bChecked;
        }
        public bool Checked {
            get { return _bChecked; }
        }
    }
    class DatagridViewCheckBoxHeaderCell : DataGridViewColumnHeaderCell {
        Point checkBoxLocation;
        Size checkBoxSize;
        bool _checked = false;
        Point _cellLocation = new Point();
        System.Windows.Forms.VisualStyles.CheckBoxState _cbState =
        System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal;
        public event CheckBoxClickedHandler OnCheckBoxClicked;

        public DatagridViewCheckBoxHeaderCell() {
        }

        protected override void Paint(System.Drawing.Graphics graphics,
        System.Drawing.Rectangle clipBounds,
        System.Drawing.Rectangle cellBounds,
        int rowIndex,
        DataGridViewElementStates dataGridViewElementState,
        object value,
        object formattedValue,
        string errorText,
        DataGridViewCellStyle cellStyle,
        DataGridViewAdvancedBorderStyle advancedBorderStyle,
        DataGridViewPaintParts paintParts) {
            base.Paint(graphics, clipBounds, cellBounds, rowIndex,
            dataGridViewElementState, value,
            formattedValue, errorText, cellStyle,
            advancedBorderStyle, paintParts);
            Point p = new Point();
            Size s = CheckBoxRenderer.GetGlyphSize(graphics,
            System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal);
            p.X = cellBounds.Location.X +
            (cellBounds.Width / 2) - (s.Width / 2);
            p.Y = cellBounds.Location.Y +
            (cellBounds.Height / 2) - (s.Height / 2);
            _cellLocation = cellBounds.Location;
            checkBoxLocation = p;
            checkBoxSize = s;
            if (_checked)
                _cbState = System.Windows.Forms.VisualStyles.
                CheckBoxState.CheckedNormal;
            else
                _cbState = System.Windows.Forms.VisualStyles.
                CheckBoxState.UncheckedNormal;
            CheckBoxRenderer.DrawCheckBox
            (graphics, checkBoxLocation, _cbState);
        }

        protected override void OnMouseClick(DataGridViewCellMouseEventArgs e) {
            Point p = new Point(e.X + _cellLocation.X, e.Y + _cellLocation.Y);
            if (p.X >= checkBoxLocation.X && p.X <=
            checkBoxLocation.X + checkBoxSize.Width
            && p.Y >= checkBoxLocation.Y && p.Y <=
            checkBoxLocation.Y + checkBoxSize.Height) {
                _checked = !_checked;
                if (OnCheckBoxClicked != null) {
                    OnCheckBoxClicked(e.ColumnIndex, _checked);
                    this.DataGridView.InvalidateCell(this);
                }
            }
            base.OnMouseClick(e);
        }

    }

    #endregion

    #region ColumnSelection

    class DataGridViewColumnSelector {
        // the DataGridView to which the DataGridViewColumnSelector is attached
        private DataGridView mDataGridView = null;
        // a CheckedListBox containing the column header text and checkboxes
        private CheckedListBox mCheckedListBox;
        // a ToolStripDropDown object used to show the popup
        private ToolStripDropDown mPopup;

        /// <summary>
        /// The max height of the popup
        /// </summary>
        public int MaxHeight = 300;
        /// <summary>
        /// The width of the popup
        /// </summary>
        public int Width = 200;

        /// <summary>
        /// Gets or sets the DataGridView to which the DataGridViewColumnSelector is attached
        /// </summary>
        public DataGridView DataGridView {
            get { return mDataGridView; }
            set {
                // If any, remove handler from current DataGridView 
                if (mDataGridView != null) mDataGridView.CellMouseClick -= new DataGridViewCellMouseEventHandler(mDataGridView_CellMouseClick);
                // Set the new DataGridView
                mDataGridView = value;
                // Attach CellMouseClick handler to DataGridView
                if (mDataGridView != null) mDataGridView.CellMouseClick += new DataGridViewCellMouseEventHandler(mDataGridView_CellMouseClick);
            }
        }

        // When user right-clicks the cell origin, it clears and fill the CheckedListBox with
        // columns header text. Then it shows the popup. 
        // In this way the CheckedListBox items are always refreshed to reflect changes occurred in 
        // DataGridView columns (column additions or name changes and so on).
        void mDataGridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e) {
            if (e.Button == MouseButtons.Right && e.RowIndex == -1 && e.ColumnIndex == 0) {
                mCheckedListBox.Items.Clear();
                foreach (DataGridViewColumn c in mDataGridView.Columns) {
                    mCheckedListBox.Items.Add(c.HeaderText, c.Visible);
                }
                int PreferredHeight = (mCheckedListBox.Items.Count * 16) + 7;
                mCheckedListBox.Height = (PreferredHeight < MaxHeight) ? PreferredHeight : MaxHeight;
                mCheckedListBox.Width = this.Width;
                mPopup.Show(mDataGridView.PointToScreen(new Point(e.X, e.Y)));
            }
        }

        // The constructor creates an instance of CheckedListBox and ToolStripDropDown.
        // the CheckedListBox is hosted by ToolStripControlHost, which in turn is
        // added to ToolStripDropDown.
        public DataGridViewColumnSelector() {
            mCheckedListBox = new CheckedListBox();
            mCheckedListBox.CheckOnClick = true;
            mCheckedListBox.ItemCheck += new ItemCheckEventHandler(mCheckedListBox_ItemCheck);

            ToolStripControlHost mControlHost = new ToolStripControlHost(mCheckedListBox);
            mControlHost.Padding = Padding.Empty;
            mControlHost.Margin = Padding.Empty;
            mControlHost.AutoSize = false;

            mPopup = new ToolStripDropDown();
            mPopup.Padding = Padding.Empty;
            mPopup.Items.Add(mControlHost);
        }

        public DataGridViewColumnSelector(DataGridView dgv)
            : this() {
            this.DataGridView = dgv;
        }

        // When user checks / unchecks a checkbox, the related column visibility is 
        // switched.
        void mCheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e) {
            mDataGridView.Columns[e.Index].Visible = (e.NewValue == CheckState.Checked);
        }
    }

    #endregion

    #endregion
}
